package com.third.bank.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.third.bank.common.IdCardLoginCommon;
import com.third.bank.common.PhoneLoginCommon;
import com.third.bank.common.UserCommon;
import com.third.bank.entity.Balance;
import com.third.bank.entity.User;
import com.third.bank.exception.BusinessException;
import com.third.bank.mapper.BalanceMapper;
import com.third.bank.mapper.UserMapper;
import com.third.bank.service.UserService;
import com.third.bank.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 客户表userServiceimpl
 */
@Service
public class UserServiceimpl extends ServiceImpl<UserMapper, User> implements UserService {
//  用户
    @Autowired
    private UserMapper userMapper;
//  余额
    @Autowired
    private BalanceMapper balanceMapper;

//  验证码工具类
    @Autowired
    private CodeUtils codeUtils;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     * 判断银行卡是否已经使用
     * @return
     */
    public boolean judgeExistIdCard(String idCard){
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(idCard != null , User::getIdCard,idCard);

        User user = userMapper.selectOne(lqw);
        return user != null;
    }

    /**
     * 判断手机号是否已经使用
     * @return
     */
    public boolean judgeExistPhone(String phone){
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(phone != null , User::getPhone,phone);

        User user = userMapper.selectOne(lqw);
        return user != null;
    }

    /**
     * 修改用户登陆状态
     * @param idCard
     * @param status
     * @return
     */
    public boolean updateLoginStatus(String idCard,int status){
        User user = searchUserbyIdcard(idCard);
        if (user != null){
            user.setLoginStatus(status);
            return userMapper.updateById(user) > 0;
        }else {
            return false;
        }

    }
    /**
     *
     * 根据银行卡号查询用户
     * @return
     */
    @Override
    public User searchUserbycard(String userBankcard) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("bank_card",userBankcard);
        User user = baseMapper.selectOne(userQueryWrapper);
        return user;
    }

    /**
     *
     * 根据身份证号查询用户
     * @return
     */
    @Override
    public User searchUserbyIdcard(String userIdCard) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("ID_card",userIdCard);
        User user = baseMapper.selectOne(userQueryWrapper);
        return user;
    }

    /**
     *
     * 根据手机号查询用户
     * @return
     */
    @Override
    public User searchUserByPhone(String phone) {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("phone",phone);
        User user = baseMapper.selectOne(userQueryWrapper);
        return user;
    }

    /**
     * 注册客户
     * 其他事务对这些数据所做的修改不会被这个事务看到。
     * 如果其他事务试图修改这些数据，它们会被阻塞，直到当前事务结束。
     * @param userCommon
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.REPEATABLE_READ )
    public BaseResponse registerUser(UserCommon userCommon) {

        //        判断，身份证是否已经注册
        boolean idFlag = judgeExistIdCard(userCommon.getIdCard());
        if (idFlag){
            throw new BusinessException(ErrorMessage.PARAMS_ERROR.getCode(),"用户账号已存在");
        }

//        判断，手机号是否已经注册
        boolean phoneFlag = judgeExistPhone(userCommon.getPhone());
        if (phoneFlag){
            throw new BusinessException(ErrorMessage.PARAMS_ERROR.getCode(),"该手机号已被注册，请跟换手机号");
        }

//        创建新的user类
        User user = new User();
        user.setUsername(userCommon.getUsername());
        user.setIdCard(userCommon.getIdCard());
        user.setSex(userCommon.getSex());
        user.setPhone(userCommon.getPhone());
        user.setMailbox(userCommon.getMailbox());
        user.setAddress(userCommon.getAddress());
        user.setWdPassword(MD5Util.getMD5(userCommon.getWdPassword()));
        user.setCreateTime(LocalDateTime.now());

//        随机生成不重复的用户银行卡卡号
        user.setBankCard(RandomBankCardUtils.generateRandomBankCardNumber());

//        将新用户写入数据库
        boolean save = userMapper.insert(user) > 0;

//        如果写入失败直接抛异常回滚
        if (!save){
            throw new BusinessException(ErrorMessage.SYSTEM_ERROR.getCode(),"系统故障，用户注册失败");
        }

//        根据id——card查询刚插入的用户获取他的id
        User newUser = searchUserbyIdcard(userCommon.getIdCard());

//        写入一条新的余额
        Balance balance = new Balance();
        balance.setUserId(newUser.getId());
        balance.setBalance(new BigDecimal(0));
        balance.setUpdateTime(LocalDateTime.now());

//        将新的余额信息写入余额表
        boolean flag = balanceMapper.insert(balance) > 0;

//        如果写入失败直接抛异常回滚
        if (!flag){
            throw new BusinessException(ErrorMessage.SYSTEM_ERROR.getCode(),"系统故障，用户注册失败");
        }

        if (save & flag){
            return ResultUtils.success(null);
        }else {
            throw new BusinessException(ErrorMessage.OPERATION_ERROR.getCode(),"用户注册失败");
        }
    }


    /**
     * 手机号登陆
     *
     * @param phoneLoginCommon
     * @return
     */
    @Override
    public BaseResponse phoneLogin(PhoneLoginCommon phoneLoginCommon) {

//        再一次验证手机号是否存在，是否已开户
        boolean flag = judgeExistPhone(phoneLoginCommon.getPhone());

        if (flag){
            //        取出缓存中的验证码
            String code = codeUtils.getCode(phoneLoginCommon.getPhone());
            //        取出受输入的验证码
            String nowCode = phoneLoginCommon.getCodeNum();
            if (nowCode.equals(code)){
//                验证码输入正确，成功登录
                User user = searchUserByPhone(phoneLoginCommon.getPhone());
                String token = JwtUtil.createToken(user);
                Map<String,Object> map = new HashMap<>();
                map.put("loginUser",user);
                map.put("token",token);

//                将生成的token放入redis
                stringRedisTemplate.opsForValue().set(token, String.valueOf(new Date().getTime()));

//                修改用户登陆状态
                updateLoginStatus(user.getIdCard(),1);

                return ResultUtils.success(map);

            }else {
//                验证码输入错误
                return ResultUtils.error(ErrorMessage.OPERATION_ERROR.getCode(),"验证码输入错误");
            }
        }else {
//            提示未开户
            return ResultUtils.error(ErrorMessage.NO_AUTH_ERROR.getCode(),"该用户尚未开户");
        }

    }


    /**
     * 身份证登陆
     *
     * @param idCardLoginCommon
     * @return
     */
    @Override
    public BaseResponse idCardLogin(IdCardLoginCommon idCardLoginCommon) {

//        验证改身份证有没有开户
        User user = searchUserbyIdcard(idCardLoginCommon.getIdCard());

        if (user != null){
//            取出数据库中的密码
            String lgPassword = user.getLgPassword();
//            取出当前输入密码
            String nowLgPassword = MD5Util.getMD5(idCardLoginCommon.getLgPassword());

            if (nowLgPassword.equals(lgPassword)){
//                密码输入正确，登陆成功
                Map<String,Object> map = new HashMap<>();
//                生成token
                String token = JwtUtil.createToken(user);
                map.put("loginUser",user);
                map.put("token",token);
//                修改用户登陆状态
                updateLoginStatus(user.getIdCard(),1);

//                将生成的token放入redis
                stringRedisTemplate.opsForValue().set(token, String.valueOf(new Date().getTime()));

                return ResultUtils.success(map);

            }else {
                return ResultUtils.error(ErrorMessage.PARAMS_ERROR.getCode(),"密码输入错误");
            }

        }else {
            //            提示未开户
            return ResultUtils.error(ErrorMessage.NO_AUTH_ERROR.getCode(),"该用户尚未开户");
        }
    }


    /**
     * 修改用户网银密码
     *
     * @param idCard   身份证
     * @param lgPassword   网银密码
     * @return
     */
    @Override
    public BaseResponse updateLgPassword(String token,String idCard, String lgPassword) {
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(idCard != null , User::getIdCard , idCard);
        User user = userMapper.selectOne(lqw);

//        确定用户已开户
        if (user != null){
//            写入新的密码
            user.setLgPassword(MD5Util.getMD5(lgPassword));
            boolean flag = userMapper.updateById(user) > 0;
//            判断是否修改成功
            if (flag){
//              退出当前登录状态，为重新登录做准备
                logout(token);
                return ResultUtils.success(null);
            }else {
                return ResultUtils.error(ErrorMessage.SYSTEM_ERROR.getCode(),"系统内部异常");
            }
        }else {
            //            提示未开户
            return ResultUtils.error(ErrorMessage.NO_AUTH_ERROR.getCode(),"该用户尚未开户");
        }
    }

    /**
     * 用户登出
     *
     * @param token
     * @return
     */
    @Override
    public BaseResponse logout(String token) {
        String idCard = JwtUtil.parse(token);
        boolean b = updateLoginStatus(idCard, 0);
//        删除redis中保存的用户token
        Boolean del = stringRedisTemplate.delete(token);

        if (b && del )
            return ResultUtils.success(null);
        else
            return ResultUtils.error(ErrorMessage.SYSTEM_ERROR.getCode(),"系统内部错误");
    }

    @Override
    public User getUserByCardId(Long cardId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getIdCard, cardId);
        return getOne(wrapper);
    }
}
